package com.fanghuaiming.test.aio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;

/****
 * @description:
 * @version:1.0.0
 * @author fanghuaiming
 * @data Created in 2021/9/25 下午8:46
 *
 */
public class SocketAioServer {

  public static void main(String[] args) throws IOException {
      AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
      assc.bind(new InetSocketAddress(8080));
      //设置回调
      assc.accept(null,new AcceptHandler(assc));
      System.in.read();
  }

  private static class  AcceptHandler implements CompletionHandler<AsynchronousSocketChannel,Object>{

      private final AsynchronousServerSocketChannel assc;

      private AcceptHandler(AsynchronousServerSocketChannel assc) {
          this.assc = assc;
      }

      @Override
      public void completed(AsynchronousSocketChannel asc, Object attachment) {
          try {
              System.out.printf("[%s] %s connected\n",Thread.currentThread().getName(),asc.getRemoteAddress());
          } catch (IOException e) {
              e.printStackTrace();
          }
          ByteBuffer buffer = ByteBuffer.allocate(16);
          //读事件由 ReadHandler 处理
          asc.read(buffer,buffer,new ReadHandler(asc));
          // 写事件由 WriteHandler 处理
          asc.write(Charset.defaultCharset().encode("hello"), ByteBuffer.allocate(16), new WriteHandler(asc));
          //处理完第一个 accpet 时,需要再次调用 accpet 方法来处理下一个 accept 事件
          assc.accept(null,this);
      }

      @Override
      public void failed(Throwable exc, Object attachment) {
        exc.printStackTrace();
      }
  }

  private static class ReadHandler implements CompletionHandler<Integer,ByteBuffer>{

      private final AsynchronousSocketChannel asc;

      private ReadHandler(AsynchronousSocketChannel asc) {
          this.asc = asc;
      }

      @Override
      public void completed(Integer result, ByteBuffer attachment) {
          try {
              if(result == -1){
                  //没读到数据就关闭当前客户端的channel
                  closeChannel(asc);
                  return;
              }
              System.out.printf("[%s] %s connected\n",Thread.currentThread().getName(),asc.getRemoteAddress());
              attachment.flip();
              System.out.println(Charset.defaultCharset().decode(attachment));
              attachment.clear();
              //处理完第一个 read 时,需要再次调用read方法来处理下一个
              asc.read(attachment,attachment,this);
          } catch (IOException e) {
              e.printStackTrace();
          }

      }

      @Override
      public void failed(Throwable exc, ByteBuffer attachment) {
          closeChannel(asc);
          exc.printStackTrace();
      }
  }

    private static void closeChannel(AsynchronousSocketChannel sc) {
        try {
            System.out.printf("[%s] %s close\n", Thread.currentThread().getName(), sc.getRemoteAddress());
            sc.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class WriteHandler implements CompletionHandler<Integer,ByteBuffer>{
      private final AsynchronousSocketChannel asc;

        private WriteHandler(AsynchronousSocketChannel asc) {
            this.asc = asc;
        }

        @Override
        public void completed(Integer result, ByteBuffer attachment) {
            //如果作为附件的buffer还有内容,需要再次write写出剩余内容
            if(attachment.hasRemaining()){
                asc.write(attachment);
            }
        }

        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            closeChannel(asc);
            exc.printStackTrace();
        }
    }
}
